import cv2
import sys
import os
import numpy

def Representationmedium(Input):
        result = int(Input)
        if result > 255:
            result = 255
        elif result < 0:
            result = 0
        else:
            result = int(result)
        return result

'''
Code from Lab2
'''
def Adjust(InputArray, Ratio, Code=0):
    cols = InputArray.shape[0]
    rows = InputArray.shape[1]
    OutputArray = numpy.zeros(InputArray.shape, dtype=InputArray.dtype)
    HLS = cv2.cvtColor(sourceImage, cv2.COLOR_BGR2HLS)
    HSV = cv2.cvtColor(sourceImage, cv2.COLOR_BGR2HSV)
    for col in range(0, cols):
        for row in range(0, rows):
            if Code == 0 or Code == 1:
                B = float(sourceImage.item(col, row, 0))
                G = float(sourceImage.item(col, row, 1))
                R = float(sourceImage.item(col, row, 2))
                if Code == 0:
                    Channel1 = B * Ratio
                    Channel2 = G * Ratio
                    Channel3 = R * Ratio
                else:
                    Channel1 = B / 255
                    Channel2 = G / 255
                    Channel3 = R / 255
                    Channel1 = ((Channel1 - 0.5) * Ratio + 0.5) * 255
                    Channel2 = ((Channel2 - 0.5) * Ratio + 0.5) * 255
                    Channel3 = ((Channel3 - 0.5) * Ratio + 0.5) * 255
            elif Code == 2:
                Channel1 = HLS.item(col, row, 0)
                Channel2 = HLS.item(col, row, 1)
                Channel3 = HLS.item(col, row, 2)
                Channel3 = Channel3 * Ratio
            elif Code == 3:
                Channel1 = HSV.item(col, row, 0)
                Channel2 = HSV.item(col, row, 1)
                Channel3 = HSV.item(col, row, 2)
                Channel1 = Channel1 + Ratio
            Channel1 = Representationmedium(Channel1)
            Channel2 = Representationmedium(Channel2)
            Channel3 = Representationmedium(Channel3)
            OutputArray.itemset(col, row, 0, Channel1)
            OutputArray.itemset(col, row, 1, Channel2)
            OutputArray.itemset(col, row, 2, Channel3)
    if Code == 2:
        return cv2.cvtColor(OutputArray, cv2.COLOR_HLS2BGR)
    elif Code == 3:
        return cv2.cvtColor(OutputArray, cv2.COLOR_HSV2BGR)
    return OutputArray

def ApplyImage(InputArray, HighPass):
    cols = InputArray.shape[0]
    rows = InputArray.shape[1]
    OutputArray = numpy.zeros(InputArray.shape, dtype=InputArray.dtype)
    for col in range(0, cols):
        for row in range(0, rows):
            Channel1 = HighPass.item(col, row, 0) - InputArray.item(col, row, 0) + 128
            Channel2 = HighPass.item(col, row, 1) - InputArray.item(col, row, 1) + 128
            Channel3 = HighPass.item(col, row, 2) - InputArray.item(col, row, 2) + 128
            Channel1 = Representationmedium(Channel1)
            Channel2 = Representationmedium(Channel2)
            Channel3 = Representationmedium(Channel3)
            OutputArray.itemset(col, row, 0, Channel1)
            OutputArray.itemset(col, row, 1, Channel2)
            OutputArray.itemset(col, row, 2, Channel3)
    return OutputArray

def ImageFusion(X, Y, Opacity):
    cols = X.shape[0]
    rows = X.shape[1]
    OutputArray = numpy.zeros(X.shape, dtype=X.dtype)
    for col in range(0, cols):
        for row in range(0, rows):
            for i in range(0, 3):
                x = X.item(col, row, i)
                y = Y.item(col, row, i)
                Channel = float(x * (100 - Opacity) + (x + 2 * y - 256) * Opacity) / 100.0
                Channel = Representationmedium(Channel)
                OutputArray.itemset(col, row, i, Channel)
    return OutputArray

if __name__ == "__main__":
    Opacity = 50
    filePath = sys.argv[1]
    fileName = os.path.basename(filePath).split('.')[0]
    sourceImage = cv2.imread(filePath)
    HighPass = sourceImage.copy()
    HighPass = Adjust(HighPass, 1.11, 1)
    HighPass = cv2.bilateralFilter(HighPass, 0, 120, 8)
    # HighPass = cv2.medianBlur(HighPass, 5)
    HighPass = cv2.pyrMeanShiftFiltering(HighPass, 10, 10)
    HighPass = ApplyImage(sourceImage, HighPass)
    HighPass = cv2.GaussianBlur(HighPass, (3, 3), 1)
    HighPass = ImageFusion(sourceImage, HighPass, Opacity)
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 2))
    HighPass = cv2.morphologyEx(HighPass, cv2.MORPH_CLOSE, kernel, iterations=1)
    cv2.imshow('result', HighPass)
    cv2.imwrite(fileName + '_result.jpg', HighPass)
    cv2.waitKey()